﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using eKanbanWPF.Model;
using eKanbanWPF.View.Statistics;
using Alias = System.Windows;

namespace eKanbanWPF
{
    /// <summary>
    /// Interaction logic for NhatTest.xaml
    /// </summary>
    public partial class NhatTest : Window
    {
        string filename;
        bool changed = false;

        eKanbanWPF.Model.KanbanBoard data;
        List<View.MemberGUI> memberGUIs = new List<View.MemberGUI>();
        List<View.TaskGUI> taskGUIs = new List<View.TaskGUI>();
        List<View.FeatureGUI> featureGUIs = new List<View.FeatureGUI>();
        List<View.PhaseGUI> phaseGUIs = new List<View.PhaseGUI>();


        FrmStatisticsNumberical frmStatistics = new FrmStatisticsNumberical();


        public static RoutedCommand OpenCommand = new RoutedCommand();
        private void OpenCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdOpen();
        }
        private void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public static RoutedCommand SaveCommand = new RoutedCommand();
        private void SaveCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdSave();
        }
        private void SaveCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public static RoutedCommand SaveAsCommand = new RoutedCommand();
        private void SaveAsCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdSaveAs();
        }
        private void SaveAsCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public static RoutedCommand NewCommand = new RoutedCommand();
        private void NewCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdNew();
        }
        private void NewCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public static RoutedCommand StatisticsCommand = new RoutedCommand();
        private void StatisticsCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdStatistics();
        }
        private void StatisticsCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public static RoutedCommand NewMemberCommand = new RoutedCommand();
        private void NewMemberCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdNewMember();
        }
        private void NewMemberCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public static RoutedCommand NewFeatureCommand = new RoutedCommand();
        private void NewFeatureCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdNewFeature();
        }
        private void NewFeatureCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public static RoutedCommand NewPhaseCommand = new RoutedCommand();
        private void NewPhaseCmdExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            cmdNewPhase();
        }
        private void NewPhaseCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public NhatTest()
        {
            InitializeComponent();

            //Command bindings
            CommandBinding cb = new CommandBinding(OpenCommand, OpenCmdExecuted, OpenCmdCanExecute);
            this.CommandBindings.Add(cb);

            cb = new CommandBinding(SaveCommand, SaveCmdExecuted, SaveCmdCanExecute);
            this.CommandBindings.Add(cb);

            cb = new CommandBinding(SaveAsCommand, SaveAsCmdExecuted, SaveAsCmdCanExecute);
            this.CommandBindings.Add(cb);

            cb = new CommandBinding(NewCommand, NewCmdExecuted, NewCmdCanExecute);
            this.CommandBindings.Add(cb);

            cb = new CommandBinding(StatisticsCommand, StatisticsCmdExecuted, StatisticsCmdCanExecute);
            this.CommandBindings.Add(cb);

            cb = new CommandBinding(NewMemberCommand, NewMemberCmdExecuted, NewMemberCmdCanExecute);
            this.CommandBindings.Add(cb);

            cb = new CommandBinding(NewFeatureCommand, NewFeatureCmdExecuted, NewFeatureCmdCanExecute);
            this.CommandBindings.Add(cb);

            cb = new CommandBinding(NewPhaseCommand, NewPhaseCmdExecuted, NewPhaseCmdCanExecute);
            this.CommandBindings.Add(cb);

            //MyCommandButton.Command = MyCommand;

            KeyGesture kg = new KeyGesture(Key.O, ModifierKeys.Control);
            InputBinding ib = new InputBinding(OpenCommand, kg);
            this.InputBindings.Add(ib);

            kg = new KeyGesture(Key.S, ModifierKeys.Control);
            ib = new InputBinding(SaveCommand, kg);
            this.InputBindings.Add(ib);

            kg = new KeyGesture(Key.S, ModifierKeys.Control | ModifierKeys.Shift);
            ib = new InputBinding(SaveAsCommand, kg);
            this.InputBindings.Add(ib);

            kg = new KeyGesture(Key.N, ModifierKeys.Control);
            ib = new InputBinding(NewCommand, kg);
            this.InputBindings.Add(ib);

            kg = new KeyGesture(Key.S, ModifierKeys.Control | ModifierKeys.Alt);
            ib = new InputBinding(StatisticsCommand, kg);
            this.InputBindings.Add(ib);

            kg = new KeyGesture(Key.M, ModifierKeys.Alt);
            ib = new InputBinding(NewMemberCommand, kg);
            this.InputBindings.Add(ib);

            kg = new KeyGesture(Key.F, ModifierKeys.Alt);
            ib = new InputBinding(NewFeatureCommand, kg);
            this.InputBindings.Add(ib);

            kg = new KeyGesture(Key.H, ModifierKeys.Alt);
            ib = new InputBinding(NewPhaseCommand, kg);
            this.InputBindings.Add(ib);

            WindowState = Alias.WindowState.Maximized;
            cmdNew();
        }

        private void clearUI()
        {
            foreach (var item in memberGUIs)
            {
                item.Member = null;
                Content.Children.Remove(item);
            }
            memberGUIs.Clear();

            foreach (var item in taskGUIs)
            {
                item.Task = null;
                Content.Children.Remove(item);
            }
            taskGUIs.Clear();

            foreach (var item in featureGUIs)
            {
                item.Feature = null;
                Content.Children.Remove(item);
            }
            featureGUIs.Clear();

            foreach (var item in phaseGUIs)
            {
                item.Phase = null;
                Content.Children.Remove(item);
            }
            phaseGUIs.Clear();
        }

        void mUI_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            Content.Children.Remove(sender as UIElement);
            Content.Children.Add(sender as UIElement);
            if (sender is View.MemberGUI)
            {

                Canvas.SetZIndex(sender as UIElement, memberGUIs.Count + taskGUIs.Count + featureGUIs.Count + phaseGUIs.Count);
            }
            else if (sender is View.TaskGUI)
            {
                Canvas.SetZIndex(sender as UIElement, taskGUIs.Count + featureGUIs.Count + phaseGUIs.Count);
            }
            else if (sender is View.FeatureGUI)
            {
                Canvas.SetZIndex(sender as UIElement, featureGUIs.Count + phaseGUIs.Count);
            }
            else if (sender is View.PhaseGUI)
            {
                Canvas.SetZIndex(sender as UIElement, featureGUIs.Count);
            }
        }

        void ControlUIChanged(object sender, EventArgs e)
        {
            changed = true;
        }

        private View.MemberGUI newMemberUI(Member m)
        {
            View.MemberGUI mUI = new View.MemberGUI();
            //((RotateTransform)this.RenderTransform).Angle = 40;

            m.Width = Math.Max(m.Width, mUI.MinWidth);
            m.Height = Math.Max(m.Height, mUI.MinHeight);

            mUI.Member = m;
            mUI.Changed += ControlUIChanged;
            mUI.PositionChanged += UnknownMember;

            this.Content.Children.Add(mUI);
            memberGUIs.Add(mUI);

            mUI.PreviewMouseDown += new MouseButtonEventHandler(mUI_PreviewMouseDown);

            return mUI;
        }

        private View.TaskGUI newTaskUI(Task t)
        {
            View.TaskGUI tUI = new View.TaskGUI();

            t.Width = Math.Max(t.Width, tUI.MinWidth);
            t.Height = Math.Max(t.Height, tUI.MinHeight);

            tUI.Task = t;
            tUI.Changed += ControlUIChanged;
            tUI.PositionChanged += UnknownTask;

            this.Content.Children.Add(tUI);
            taskGUIs.Add(tUI);
            tUI.PreviewMouseDown += new MouseButtonEventHandler(mUI_PreviewMouseDown);

            return tUI;
        }

        private View.FeatureGUI newFeatureUI(Feature f)
        {
            View.FeatureGUI fUI = new View.FeatureGUI();

            f.Width = Math.Max(f.Width, fUI.MinWidth);
            f.Height = Math.Max(f.Height, fUI.MinHeight);

            fUI.Feature = f;
            fUI.Changed += ControlUIChanged;
            fUI.PositionChanged += UnknownFeature;

            this.Content.Children.Add(fUI);
            featureGUIs.Add(fUI);
            fUI.PreviewMouseDown += new MouseButtonEventHandler(mUI_PreviewMouseDown);

            return fUI;
        }

        private View.PhaseGUI newPhaseUI(BasePhase p)
        {
            View.PhaseGUI pUI = new View.PhaseGUI();

            p.Width = Math.Max(p.Width, 200);
            p.Height = Math.Max(p.Height, pUI.MinHeight);

            pUI.Phase = p;
            pUI.Changed += ControlUIChanged;
            this.Content.Children.Add(pUI);
            phaseGUIs.Add(pUI);
            pUI.PreviewMouseDown += new MouseButtonEventHandler(mUI_PreviewMouseDown);

            List<Model.BasePhase> list = new List<BasePhase>();
            list.Add(data.BeginPhase);
            foreach (var item in data.Phases)
            {
                list.Add(item);
            }
            list.Add(data.EndPhase);
            View.FrmPhase.setSource(list);

            return pUI;
        }

        private void LoadData(string fileName)
        {
            try
            {
                data = eKanbanWPF.Model.KanbanBoard.Load(fileName);
            }
            catch (Exception e)
            {
                MessageBox.Show("Invalid data file.", "Loading error...", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
                return;
            }

            this.filename = fileName;

            clearUI();
            int count = 0;

            var pUI = newPhaseUI(data.BeginPhase);
            Canvas.SetZIndex(pUI, count++);
            foreach (var p in data.Phases)
            {
                pUI = newPhaseUI(p);
                Canvas.SetZIndex(pUI, count++);
            }
            pUI = newPhaseUI(data.EndPhase);
            Canvas.SetZIndex(pUI, count++);

            foreach (var f in data.Features)
            {
                var fUI = newFeatureUI(f);
                Canvas.SetZIndex(fUI, count++);
            }

            foreach (var t in data.Tasks)
            {
                var tUI = newTaskUI(t);
                Canvas.SetZIndex(tUI, count++);
            }

            foreach (var m in data.Members)
            {
                var mUI = newMemberUI(m);
                Canvas.SetZIndex(mUI, count++);
            }
        }

        private void cmdNew()
        {
            if (changed)
            {
                var res = MessageBox.Show("Do you want to save before open a new document ?", "Save ?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Yes);
                if (res == MessageBoxResult.Cancel)
                {
                    return;
                }
                if (res == MessageBoxResult.Yes)
                {
                    cmdSave();
                }
            }


            clearUI();
            data = new KanbanBoard("Backlog", "Done");
            data.BeginPhase.Top = 200;
            data.BeginPhase.Left = 0;
            data.EndPhase.Top = 200;
            //data.EndPhase.Left = this.Width - 250;
            data.EndPhase.Left = 600 - 250;
            newPhaseUI(data.BeginPhase);
            newPhaseUI(data.EndPhase);
            filename = null;
            changed = false;
            List<Model.BasePhase> list = new List<BasePhase>();
            list.Add(data.BeginPhase);
            foreach (var item in data.Phases)
            {
                list.Add(item);
            }
            list.Add(data.EndPhase);
            View.FrmPhase.setSource(list);
        }

        private void cmdOpen()
        {
            if (changed)
            {
                var res = MessageBox.Show("Do you want to save before open another new document ?", "Save ?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Yes);
                if (res == MessageBoxResult.Cancel)
                {
                    return;
                }
                if (res == MessageBoxResult.Yes)
                {
                    cmdSave();
                }
            }


            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            // Set filter for file extension and default file extension
            dlg.DefaultExt = ".ekb";
            dlg.Filter = "Kanban documents (.ekb)|*.ekb";
            // Display OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = dlg.ShowDialog();
            // Get the selected file name and display in a TextBox
            if (result == true)
            {
                // Open document
                string filename = dlg.FileName;
                LoadData(filename);
                List<Model.BasePhase> list = new List<BasePhase>();
                list.Add(data.BeginPhase);
                foreach (var item in data.Phases)
                {
                    list.Add(item);
                }
                list.Add(data.EndPhase);
                View.FrmPhase.setSource(list);
                changed = false;
            }
        }

        private void cmdSaveAs()
        {
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            // Set filter for file extension and default file extension
            dlg.DefaultExt = ".ekb";
            dlg.Filter = "Kanban documents (.ekb)|*.ekb";
            Nullable<bool> result = dlg.ShowDialog();
            // Get the selected file name and display in a TextBox
            if (result == true)
            {
                // Open document
                filename = dlg.FileName;
                save(filename);
                changed = false;
            }
        }

        private void save(string filename)
        {
            Dictionary<View.MemberGUI, Member> mbackup = new Dictionary<View.MemberGUI, Member>();
            Dictionary<View.TaskGUI, Task> tbackup = new Dictionary<View.TaskGUI, Task>();
            Dictionary<View.FeatureGUI, Feature> fbackup = new Dictionary<View.FeatureGUI, Feature>();
            Dictionary<View.PhaseGUI, BasePhase> pbackup = new Dictionary<View.PhaseGUI, BasePhase>();
            //Remove Listener;
            foreach (var item in memberGUIs)
            {
                mbackup[item] = item.Member;
                item.Member.Top = Canvas.GetTop(item);
                item.Member.Left = Canvas.GetLeft(item);
                item.Member.Width = item.Width;
                item.Member.Height = item.Height;
                item.Member = null;
            }


            foreach (var item in taskGUIs)
            {
                tbackup[item] = item.Task;
                item.Task.Top = Canvas.GetTop(item);
                item.Task.Left = Canvas.GetLeft(item);
                item.Task.Width = item.Width;
                item.Task.Height = item.Height;
                item.Task = null;
            }


            foreach (var item in featureGUIs)
            {
                fbackup[item] = item.Feature;
                item.Feature.Top = Canvas.GetTop(item);
                item.Feature.Left = Canvas.GetLeft(item);
                item.Feature.Width = item.Width;
                item.Feature.Height = item.Height;
                item.Feature = null;
            }


            foreach (var item in phaseGUIs)
            {
                pbackup[item] = item.Phase;
                item.Phase.Top = Canvas.GetTop(item);
                item.Phase.Left = Canvas.GetLeft(item);
                item.Phase.Width = item.Width;
                item.Phase.Height = item.Height;
                item.Phase = null;
            }


            KanbanBoard.Save(filename, data);

            //Restore Listener;
            foreach (var item in memberGUIs)
            {
                item.Member = mbackup[item];
            }


            foreach (var item in taskGUIs)
            {
                item.Task = tbackup[item];
            }


            foreach (var item in featureGUIs)
            {
                item.Feature = fbackup[item];
            }


            foreach (var item in phaseGUIs)
            {
                item.Phase = pbackup[item];
            }

        }

        private void cmdSave()
        {
            if (filename == null)
            {
                cmdSaveAs();
            }
            else
            {
                save(filename);
                changed = false;
            }
        }

        private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
        }


        ContentControl hitTestResult;
        Visual hitTestParent;
        System.Windows.Media.HitTestResultBehavior HitTestCallback(HitTestResult result)
        {
            if (result.VisualHit is ContentControl)
            {
                var item = result.VisualHit as ContentControl;
                if (item.Parent == hitTestParent)
                {
                    hitTestResult = item;
                    return System.Windows.Media.HitTestResultBehavior.Stop;
                }
            }
            return System.Windows.Media.HitTestResultBehavior.Continue;
        }

        private ContentControl GetChildAtPoint(Visual parent, Point point)
        {
            hitTestResult = null;
            hitTestParent = parent;
            VisualTreeHelper.HitTest(parent, null, new HitTestResultCallback(HitTestCallback), new PointHitTestParameters(point));
            return hitTestResult;
        }

        private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {

            var item = VisualTreeHelper.HitTest(Content, Mouse.GetPosition(Content));

            if (item == null)
            {
                if (this.WindowState != Alias.WindowState.Maximized)
                {
                    this.WindowState = Alias.WindowState.Maximized;
                }
                else
                {
                    this.WindowState = Alias.WindowState.Normal;
                }
            }
            else
            {

            }
        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape && WindowState == Alias.WindowState.Maximized)
            {
                WindowState = Alias.WindowState.Normal;
            }
        }

        private void imageCLose_MouseDown(object sender, MouseButtonEventArgs e)
        {
            cmdClose();
        }

        private void menu1_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

        }

        private void menu1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //base.OnMouseLeftButtonDown(e);
            e.Handled = true;
        }

        private void mnuNew_Click(object sender, RoutedEventArgs e)
        {
            cmdNew();
        }

        private void mnuOpen_Click(object sender, RoutedEventArgs e)
        {

            cmdOpen();
        }

        private void mnuSave_Click(object sender, RoutedEventArgs e)
        {
            cmdSave();
        }

        private void mnuSaveAs_Click(object sender, RoutedEventArgs e)
        {
            cmdSaveAs();
        }

        private void cmdStatistics()
        {
            Statistics.GetStatistics(data, frmStatistics.data);
            frmStatistics.ShowDialog();
        }
        private void mnuStatistics_Click(object sender, RoutedEventArgs e)
        {
            cmdStatistics();
        }

        private void cmdNewMember()
        {
            var m = data.DefineNewMember("New Member", true, "");
            var UI = newMemberUI(m);
            UI.Focus();
            Selector.SetIsSelected(UI, true);
        }
        private void mnuNewMember_Click(object sender, RoutedEventArgs e)
        {
            cmdNewMember();
        }

        private void cmdNewFeature()
        {
            var f = data.DefineNewFeature("New feature", "Description of new feature", 3);
            var UI = newFeatureUI(f);
            UI.Focus();
            Selector.SetIsSelected(UI, true);
        }
        private void mnuNewFeature_Click(object sender, RoutedEventArgs e)
        {
            cmdNewFeature();
        }

        private void cmdNewPhase()
        {
            var p = data.DefineNewPhase("New Phase", "How to be considered as done.", 3);
            var UI = newPhaseUI(p);
            UI.Focus();
            Selector.SetIsSelected(UI, true);
        }
        private void mnuNewPhase_Click(object sender, RoutedEventArgs e)
        {
            cmdNewPhase();
        }

        private void cmdClose()
        {
            if (changed)
            {
                var res = MessageBox.Show("Do you want to save before quit ?", "Save ?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Yes);
                if (res == MessageBoxResult.Cancel)
                {
                    return;
                }
                if (res == MessageBoxResult.Yes)
                {
                    cmdSave();
                }
            }
            changed = false;
            this.Close();
        }
        private void mnuExit_Click(object sender, RoutedEventArgs e)
        {
            cmdClose();
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            cmdOpen();
        }

        private bool Overlap(UserControl father, UserControl child)
        {
            double a = Canvas.GetLeft(father);
            double b = Canvas.GetTop(father);

            double _a = Canvas.GetLeft(child);
            double _b = Canvas.GetTop(child);

            if ((_b + child.Height <= b) || (_a + child.Width <= a) ||
                (_b >= father.Height + b) || (_a >= father.Width + a))
            {
                return false;
            }
            return true;
        }

        // don't know how to name this
        private void UnknownMember(View.MemberGUI memberGui)
        {
            View.TaskGUI tmp = null;
            foreach (View.TaskGUI item in taskGUIs)
            {
                if (Overlap(item, memberGui))
                {
                    if (tmp == null || Canvas.GetZIndex(tmp) < Canvas.GetZIndex(item))
                    {
                        tmp = item;
                    }
                }
            }
            
            if (tmp != null)
            {
                Model.Task task = tmp.Task;
                Model.Member member = memberGui.Member;

                member.Take(task);
            }            
            else { memberGui.Member.Take(null); }
        }

        // don't know how to name this
        private void UnknownTask(View.TaskGUI taskGui)
        {
            //View.FeatureGUI tmp = null;
            //foreach (View.FeatureGUI item in featureGUIs)
            //{
            //    if (Overlap(item, taskGui))
            //    {
            //        if (tmp == null || Canvas.GetZIndex(tmp) < Canvas.GetZIndex(item))
            //        {
            //            tmp = item;
            //        }
            //    }
            //}

            //if (tmp != null)
            //{
            //    Model.Task task = taskGui.Task;
            //    Model.Feature feature = tmp.Feature;

            //    //member.Take(task);
            //}
            Model.Task task = taskGui.Task;
            UserControl tmp = new UserControl();
            foreach (View.MemberGUI item in memberGUIs)
            {
                if (Overlap(taskGui, item))
                {
                    taskGui.Task.AddNewMember(item.Member);
                }
                else
                {
                    taskGui.Task.RemoveMember(item.Member);
                }
            }
        }

        // don't know how to name this
        private void UnknownFeature(View.FeatureGUI featureGui)
        {
            View.PhaseGUI tmp = null;
            foreach (View.PhaseGUI item in phaseGUIs)
            {
                if (Overlap(item, featureGui))
                {
                    if (tmp == null || Canvas.GetZIndex(tmp) < Canvas.GetZIndex(item))
                    {
                        tmp = item;
                    }
                }
            }

            if (tmp != null)
            {
                Model.BasePhase phase = tmp.Phase;
                Model.Feature feature = featureGui.Feature;

                try
                {
                    feature.Move(phase);
                }
                catch (Exception)
                {
                    if (tmp.Phase != feature.CurrentPhase)
                    {
                        DevExpress.XtraEditors.XtraMessageBox.Show("Cannot move to this phase\nTask still in previous phase", "Error", Alias.Forms.MessageBoxButtons.OK, Alias.Forms.MessageBoxIcon.Error); 
                    }
                }
            }
        }
    }
}
